import { 
  STORAGE_ERROR_CODES, 
  STORAGE_EVENTS,
  type StorageErrorCode,
  type StorageEvent
} from '@/constants/storage';

/**
 * 会话存储数据包装接口
 * @description 包装会话存储数据的元信息
 */
export interface ISessionStorageWrapper<T = unknown> {
  /** 实际数据 */
  data: T;
  /** 创建时间戳 */
  createdAt: number;
  /** 更新时间戳 */
  updatedAt: number;
  /** 数据类型标识 */
  type?: string;
  /** 会话ID */
  sessionId?: string;
}

/**
 * 会话存储操作结果接口
 */
export interface ISessionStorageResult<T = unknown> {
  /** 操作是否成功 */
  success: boolean;
  /** 返回的数据 */
  data?: T;
  /** 错误代码 */
  errorCode?: StorageErrorCode;
  /** 错误信息 */
  errorMessage?: string;
  /** 操作时间戳 */
  timestamp: number;
}

/**
 * 会话存储统计信息接口
 */
export interface ISessionStorageStats {
  /** 已使用的存储空间（字节） */
  usedSpace: number;
  /** 存储项数量 */
  itemCount: number;
  /** 会话开始时间 */
  sessionStartTime: number;
  /** 当前会话ID */
  sessionId: string;
}

/**
 * 会话存储工具类
 * @description 提供增强的会话存储功能，包括数据包装、类型安全、统计信息等
 */
export class SessionStorageUtils {
  private static readonly EVENT_TARGET = new EventTarget();
  private static sessionId: string = SessionStorageUtils.generateSessionId();

  /**
   * 存储数据到会话存储
   * @param key 存储键
   * @param data 要存储的数据
   * @param options 存储选项
   * @returns 存储结果
   */
  static setItem<T>(
    key: string, 
    data: T, 
    options: {
      /** 数据类型标识 */
      type?: string;
      /** 是否包含会话ID */
      includeSessionId?: boolean;
    } = {}
  ): ISessionStorageResult<T> {
    try {
      const now = Date.now();

      const wrapper: ISessionStorageWrapper<T> = {
        data,
        createdAt: now,
        updatedAt: now,
        type: options.type,
        sessionId: options.includeSessionId ? this.sessionId : undefined
      };

      const serializedData = JSON.stringify(wrapper);

      // 检查数据大小（会话存储通常比本地存储限制更小）
      const dataSize = new Blob([serializedData]).size;
      const maxSize = 5 * 1024 * 1024; // 5MB 限制
      if (dataSize > maxSize) {
        return {
          success: false,
          errorCode: STORAGE_ERROR_CODES.QUOTA_EXCEEDED,
          errorMessage: `数据大小超过限制：${dataSize} > ${maxSize}`,
          timestamp: now
        };
      }

      // 存储数据
      sessionStorage.setItem(key, serializedData);

      // 触发数据变更事件
      this.dispatchEvent(STORAGE_EVENTS.DATA_CHANGED, { key, action: 'set', data });

      return {
        success: true,
        data,
        timestamp: now
      };

    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : '存储数据失败';
      const errorCode = error instanceof DOMException && error.name === 'QuotaExceededError' 
        ? STORAGE_ERROR_CODES.QUOTA_EXCEEDED 
        : STORAGE_ERROR_CODES.UNKNOWN_ERROR;

      return {
        success: false,
        errorCode,
        errorMessage,
        timestamp: Date.now()
      };
    }
  }

  /**
   * 从会话存储获取数据
   * @param key 存储键
   * @returns 存储结果
   */
  static getItem<T>(key: string): ISessionStorageResult<T> {
    try {
      const serializedData = sessionStorage.getItem(key);
      
      if (!serializedData) {
        return {
          success: false,
          errorCode: STORAGE_ERROR_CODES.INVALID_DATA_FORMAT,
          errorMessage: '数据不存在',
          timestamp: Date.now()
        };
      }

      const wrapper: ISessionStorageWrapper<T> = JSON.parse(serializedData);

      return {
        success: true,
        data: wrapper.data,
        timestamp: Date.now()
      };

    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : '读取数据失败';
      return {
        success: false,
        errorCode: STORAGE_ERROR_CODES.INVALID_DATA_FORMAT,
        errorMessage,
        timestamp: Date.now()
      };
    }
  }

  /**
   * 从会话存储删除数据
   * @param key 存储键
   * @returns 操作结果
   */
  static removeItem(key: string): ISessionStorageResult<void> {
    try {
      const existingData = this.getItem(key);
      sessionStorage.removeItem(key);

      // 触发数据变更事件
      this.dispatchEvent(STORAGE_EVENTS.DATA_CHANGED, { 
        key, 
        action: 'remove', 
        data: existingData.success ? existingData.data : null 
      });

      return {
        success: true,
        timestamp: Date.now()
      };

    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : '删除数据失败';
      return {
        success: false,
        errorCode: STORAGE_ERROR_CODES.UNKNOWN_ERROR,
        errorMessage,
        timestamp: Date.now()
      };
    }
  }

  /**
   * 清空会话存储
   * @param prefix 键名前缀（可选，只清空指定前缀的数据）
   * @returns 操作结果
   */
  static clear(prefix?: string): ISessionStorageResult<void> {
    try {
      if (prefix) {
        // 只清空指定前缀的数据
        const keysToRemove: string[] = [];
        for (let i = 0; i < sessionStorage.length; i++) {
          const key = sessionStorage.key(i);
          if (key && key.startsWith(prefix)) {
            keysToRemove.push(key);
          }
        }
        keysToRemove.forEach(key => sessionStorage.removeItem(key));
      } else {
        // 清空所有数据
        sessionStorage.clear();
      }

      // 触发数据变更事件
      this.dispatchEvent(STORAGE_EVENTS.DATA_CHANGED, { 
        key: prefix || 'all', 
        action: 'clear', 
        data: null 
      });

      return {
        success: true,
        timestamp: Date.now()
      };

    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : '清空数据失败';
      return {
        success: false,
        errorCode: STORAGE_ERROR_CODES.UNKNOWN_ERROR,
        errorMessage,
        timestamp: Date.now()
      };
    }
  }

  /**
   * 检查键是否存在
   * @param key 存储键
   * @returns 是否存在
   */
  static hasItem(key: string): boolean {
    const result = this.getItem(key);
    return result.success;
  }

  /**
   * 获取所有键名
   * @param prefix 键名前缀（可选）
   * @returns 键名数组
   */
  static getKeys(prefix?: string): string[] {
    const keys: string[] = [];
    for (let i = 0; i < sessionStorage.length; i++) {
      const key = sessionStorage.key(i);
      if (key && (!prefix || key.startsWith(prefix))) {
        keys.push(key);
      }
    }
    return keys;
  }

  /**
   * 获取会话存储统计信息
   * @returns 统计信息
   */
  static getStats(): ISessionStorageStats {
    let usedSpace = 0;
    let itemCount = 0;

    for (let i = 0; i < sessionStorage.length; i++) {
      const key = sessionStorage.key(i);
      if (key) {
        const value = sessionStorage.getItem(key);
        if (value) {
          usedSpace += new Blob([value]).size;
          itemCount++;
        }
      }
    }

    return {
      usedSpace,
      itemCount,
      sessionStartTime: this.getSessionStartTime(),
      sessionId: this.sessionId
    };
  }

  /**
   * 获取当前会话ID
   * @returns 会话ID
   */
  static getSessionId(): string {
    return this.sessionId;
  }

  /**
   * 重新生成会话ID
   * @returns 新的会话ID
   */
  static regenerateSessionId(): string {
    this.sessionId = this.generateSessionId();
    return this.sessionId;
  }

  /**
   * 获取会话开始时间
   * @returns 会话开始时间戳
   */
  static getSessionStartTime(): number {
    const result = this.getItem<number>('__session_start_time__');
    if (!result.success) {
      const startTime = Date.now();
      this.setItem('__session_start_time__', startTime);
      return startTime;
    }
    return result.data!;
  }

  /**
   * 获取会话持续时间
   * @returns 会话持续时间（毫秒）
   */
  static getSessionDuration(): number {
    return Date.now() - this.getSessionStartTime();
  }

  /**
   * 备份会话数据到本地存储
   * @param keys 要备份的键名数组（可选，默认备份所有）
   * @returns 备份结果
   */
  static backupToLocalStorage(keys?: string[]): ISessionStorageResult<{ backedUpCount: number }> {
    try {
      const keysToBackup = keys || this.getKeys();
      let backedUpCount = 0;

      keysToBackup.forEach(key => {
        const result = this.getItem(key);
        if (result.success) {
          const backupKey = `session_backup_${key}`;
          localStorage.setItem(backupKey, JSON.stringify({
            data: result.data,
            sessionId: this.sessionId,
            backedUpAt: Date.now()
          }));
          backedUpCount++;
        }
      });

      return {
        success: true,
        data: { backedUpCount },
        timestamp: Date.now()
      };

    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : '备份数据失败';
      return {
        success: false,
        errorCode: STORAGE_ERROR_CODES.BACKUP_FAILED,
        errorMessage,
        timestamp: Date.now()
      };
    }
  }

  /**
   * 从本地存储恢复会话数据
   * @param sessionId 要恢复的会话ID（可选）
   * @returns 恢复结果
   */
  static restoreFromLocalStorage(sessionId?: string): ISessionStorageResult<{ restoredCount: number }> {
    try {
      let restoredCount = 0;
      const targetSessionId = sessionId || this.sessionId;

      for (let i = 0; i < localStorage.length; i++) {
        const key = localStorage.key(i);
        if (key && key.startsWith('session_backup_')) {
          try {
            const backupData = JSON.parse(localStorage.getItem(key)!);
            if (!sessionId || backupData.sessionId === targetSessionId) {
              const originalKey = key.replace('session_backup_', '');
              this.setItem(originalKey, backupData.data);
              restoredCount++;
            }
          } catch {
            // 忽略解析错误的备份数据
          }
        }
      }

      return {
        success: true,
        data: { restoredCount },
        timestamp: Date.now()
      };

    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : '恢复数据失败';
      return {
        success: false,
        errorCode: STORAGE_ERROR_CODES.RESTORE_FAILED,
        errorMessage,
        timestamp: Date.now()
      };
    }
  }

  /**
   * 添加事件监听器
   * @param eventType 事件类型
   * @param listener 事件监听器
   */
  static addEventListener(eventType: StorageEvent, listener: EventListener): void {
    this.EVENT_TARGET.addEventListener(eventType, listener);
  }

  /**
   * 移除事件监听器
   * @param eventType 事件类型
   * @param listener 事件监听器
   */
  static removeEventListener(eventType: StorageEvent, listener: EventListener): void {
    this.EVENT_TARGET.removeEventListener(eventType, listener);
  }

  /**
   * 生成会话ID
   * @returns 会话ID
   */
  private static generateSessionId(): string {
    const timestamp = Date.now().toString(36);
    const randomStr = Math.random().toString(36).substr(2, 9);
    return `session_${timestamp}_${randomStr}`;
  }

  /**
   * 触发事件
   * @param eventType 事件类型
   * @param detail 事件详情
   */
  private static dispatchEvent(eventType: StorageEvent, detail: unknown): void {
    const event = new CustomEvent(eventType, { detail });
    this.EVENT_TARGET.dispatchEvent(event);
  }
}

/**
 * 导出便捷函数
 */

/**
 * 存储会话数据
 */
export const setSessionStorage = <T>(key: string, data: T, options?: Parameters<typeof SessionStorageUtils.setItem>[2]) => 
  SessionStorageUtils.setItem(key, data, options);

/**
 * 获取会话数据
 */
export const getSessionStorage = <T>(key: string) => 
  SessionStorageUtils.getItem<T>(key);

/**
 * 删除会话数据
 */
export const removeSessionStorage = (key: string) => 
  SessionStorageUtils.removeItem(key);

/**
 * 检查会话键是否存在
 */
export const hasSessionStorage = (key: string) => 
  SessionStorageUtils.hasItem(key);

/**
 * 获取会话存储统计
 */
export const getSessionStorageStats = () => 
  SessionStorageUtils.getStats();

/**
 * 获取当前会话ID
 */
export const getCurrentSessionId = () => 
  SessionStorageUtils.getSessionId();

/**
 * 获取会话持续时间
 */
export const getSessionDuration = () => 
  SessionStorageUtils.getSessionDuration();